
import random
import plugin

from game import Hall, DISCARD_COMMAND
from Bang_Card import get_draw_cards, get_character_cards, get_role_cards

class BangHall(Hall):
    def __init__(self, admin, profile, conf, conn, reactor, users=[]):
        users = users[:]
        users.append(admin)
        Hall.__init__(self, profile, conf, conn, reactor, users)
        self.__admin = admin
        self.__game_flag = False
        plugin.command_plugin.Cmd_Roll().PlugIn(self)

    def start(self):
        user_num = len(self.user_list)
        if user_num < 4:
            self.systoall("we don't have enough people to start the game.")
            return
        elif user_num > 7:
            self.systoall("we have too many people to play the game.")
            return

        self.__draw_cards = get_draw_cards(user_num)
        self.__character_cards = get_character_cards()
        self.__role_cards = get_role_cards(user_num)
        self.__public_cards = []
        self.__users = {}

        for player in self.user_list: self.init_player(player)

        self.__game_flag = True
        self.systoall("== Game Start ==")

    def init_player(self, player):
        role = self.__role_cards.get_random()[0]
        character = self.__character_cards.get_random()[0]
        life = int(character['Life'])
        is_sheriff = (role['Name'] == 'Sheriff')
        if is_sheriff: self.systoall('%s is the Sheriff!' % player)
        self.__users[player] = {
            'role': role,
            'character': character,
            'hp': life,
            'equip': [],
            'hand': self.__draw_cards.get_random(life),
            'is_sheriff': is_sheriff
            }

    def startHandler(self, who, msg):
        '"/start" start a new game. only for admin.'
        if self.getindexname(who) != self.__admin:
            self.systoone(who, "Only for admin.")
        elif self.__game_flag:
            self.systoone(who, "The game has already started.")
        else:
            self.start()

    def hpHandler(self, who, msg):
        "/hp val"
        if not self.__game_flag:
            self.systoone(who, 'Please wait until the game starts.')
            return
        try:
            val = int(msg.strip())
            u = self.__users[self.getindexname(who)]
            o_hp = u['hp']
            u['hp'] += val
            op = (val >= 0 and '+' or '')
            self.systoall('%s\'s hp changed: %d%s%d=%d'%(self.getdisplayname(who), o_hp, op, val, u['hp']))
        except ValueError:
            self.systoone(who, 'Usage: /hp 1/-1/2/-2/...')

    def dealHandler(self, who, msg):
        "/deal card_num"
        if not self.__game_flag:
            self.systoone(who, 'Please wait until the game starts.')
            return
        try:
            num = int(msg.strip())
            u = self.__users[self.getindexname(who)]
            if len(self.__draw_cards) < num:
                self.systoall('%s wants to deal %d cards, but the cards in deck(%d cards available) is not enough.' % (self.getdisplayname(who), num, len(self.__draw_cards)))
            else:
                cards = self.__draw_cards.get_random(num)
                u['hand'].extend(cards)
                self.systoall('%s deal %d cards.' % (self.getdisplayname(who), num))
                self.systoone(who, 'you dealed:\n' + self.readCards(cards))
        except ValueError:
            self.systoone(who, 'Usage: /deal card_num')

    def dealtopHandler(self, who, msg):
        "/dealtop"
        if not self.__game_flag:
            self.systoone(who, 'Please wait until the game starts.')
            return
        card = self.__draw_cards.get_random()[0]
        self.systoall(self.getdisplayname(who) + ' deal top:\n' + self.readCard(card))
        self.__draw_cards.append(card)

    def dealpublicHandler(self, who, msg):
        '"/dealpublic n" deal n cards to public'
        if not self.__game_flag:
            self.systoone(who, 'Please wait until the game starts.')
            return
        try:
            num = int(msg.strip())
            cards = self.__draw_cards.get_random(num)
            self.__public_cards.extend (cards)
            self.systoall('%s deals %d public cards:\n%s' % (
                self.getdisplayname(who),
                num,
                self.readCards(cards)
                ))
        except ValueError:
            self.systoone(who, 'Usage: /dealpublic n (n must be Integer)')

    def equipHandler(self, who, msg):
        "/equip card_name"
        if not self.__game_flag:
            self.systoone(who, 'Please wait until the game starts.')
            return
        u = self.__users[self.getindexname(who)]
        request_card = msg.strip()
        find_cards = self.findCards (request_card, u['hand'])
        if len(find_cards) > 0:
            u['hand'].remove(find_cards[0])
            u['equip'].append(find_cards[0])
            self.systoall('%s equiped card [%s]' % (self.getdisplayname(who), request_card))
        else:
            self.systoone(who, 'Cannot find specified card [%s]' % request_card)

    def findCards(self, request_card, cards):
        'find cards named request_card in given cards'
        return [c for c in cards if c['CardName'].lower().strip('!') == request_card.lower().strip('!')]

    def discardHandler(self, who, msg):
        '"/discard card_name" discard a card from your hand.'
        if not self.__game_flag:
            self.systoone(who, 'Please wait until the game starts.')
            return
        u = self.__users[self.getindexname(who)]
        request_card = msg.strip()
        find_cards = self.findCards(request_card, u['hand'])
        if len(find_cards) > 0:
            u['hand'].remove(find_cards[0])
            self.__draw_cards.append(find_cards[0])
            self.systoall('%s discard a card [%s]' % (self.getdisplayname(who), request_card))
        else:
            self.systoone(who, 'Cannot find specified card [%s] from your hand.' % request_card)

    def discardequipHandler(self, who, msg):
        '"/discardequip card_name" discard a equipped card.'
        if not self.__game_flag:
            self.systoone(who, 'Please wait until the game starts.')
            return
        u = self.__users[self.getindexname(who)]
        request_card = msg.strip()
        find_cards = self.findCards(request_card, u['equip'])
        if len(find_cards) > 0:
            u['equip'].remove(find_cards[0])
            self.__draw_cards.append(find_cards[0])
            self.systoall('%s discard a equip card [%s]' % (self.getdisplayname(who), request_card))
        else:
            self.systoone(who, 'Cannot find specified card [%s] from your equipments.' % request_card)

    def discardrandomHandler(self, who, msg):
        '"/discardrandom" discard a card from your hand randomly.'
        if not self.__game_flag:
            self.systoone(who, 'Please wait until the game starts.')
            return
        u = self.__users[self.getindexname(who)]
        if len(u['hand']) > 0:
            card = random.choice(u['hand'])
            u['hand'].remove(card)
            self.__draw_cards.append(card)
            self.systoall('%s discard a card [%s] randomly.' % (self.getdisplayname(who), card['CardName']))
        else:
            self.systoone(who, 'There is no card in your hand.')

    def giveHandler(self, who, msg):
        '"/give player card_name" give a player a card from your hand.'
        if not self.__game_flag:
            self.systoone(who, 'Please wait until the game starts.')
            return
        tokens = msg.split()
        if len(tokens) != 2:
            self.systoone(who, 'Usage: /give player card_name')
            return
        
        request_player = tokens[0]
        request_card = tokens[1]
        if self.getindexname(request_player) not in self.user_list:
            self.systoone(who, 'Cannot find specified player [%s]' % request_player)
            return

        u = self.__users[self.getindexname(who)]
        find_cards = self.findCards(request_card, u['hand'])
        if len(find_cards) == 0:
            self.systoone(who, 'Cannot find specified card [%s] in your hand.' % request_card)
            return

        utarget = self.__users[self.getindexname(request_player)]
        u['hand'].remove(find_cards[0])
        utarget['hand'].append(find_cards[0])
        self.systoall('%s give card [%s] to %s' % (self.getdisplayname(who), request_card, request_player))

    def giveeqiupHandler(self, who, msg):
        '"/giveequip player card_name" give a player a card from your equipments.'
        if not self.__game_flag:
            self.systoone(who, 'Please wait until the game starts.')
            return
        tokens = msg.split()
        if len(tokens) != 2:
            self.systoone(who, 'Usage: /give player card_name')
            return
        
        request_player = tokens[0]
        request_card = tokens[1]
        if self.getindexname(request_player) not in self.user_list:
            self.systoone(who, 'Cannot find specified player [%s]' % request_player)
            return

        u = self.__users[self.getindexname(who)]
        find_cards = self.findCards(request_card, u['equip'])
        if len(find_cards) == 0:
            self.systoone(who, 'Cannot find specified card [%s] in your equipments.' % request_card)
            return

        utarget = self.__users[self.getindexname(request_player)]
        u['equip'].remove(find_cards[0])
        utarget['hand'].append(find_cards[0])
        self.systoall('%s give equipped card [%s] to %s' % (self.getdisplayname(who), request_card, request_player))
        
    def giverandomHandler(self, who, msg):
        '"/giverandom player" give a player a card from your hand randomly.'
        if not self.__game_flag:
            self.systoone(who, 'Please wait until the game starts.')
            return
        request_player = msg.strip()
        if self.getindexname(request_player) not in self.user_list:
            self.systoone(who, 'Cannot find specified player [%s]' % request_player)
            return

        u = self.__users[self.getindexname(who)]
        if len(u['hand']) == 0:
            self.systoone(who, 'There is no card in your hand.')
            return

        card = random.choice(u['hand'])
        utarget = self.__users[self.getindexname(request_player)]
        u['hand'].remove(card)
        utarget['hand'].append(card)
        self.systoall('%s give card [%s] to %s randomly.' % (self.getdisplayname(who), card['CardName'], request_player))

    def takeHandler(self, who, msg):
        '"/take [card_name]" take one of public cards.'
        if not self.__game_flag:
            self.systoone(who, 'Please wait until the game starts.')
            return
        if len(self.__public_cards) == 0:
            self.systoone(who, 'There is no card in public.')
            return
            
        request_card = msg.strip()
        if len(request_card) == 0:
            find_cards = [random.choice(self.__public_cards)]
        else:
            find_cards = self.findCards(request_card, self.__public_cards)
        if len(find_cards) > 0:
            u = self.__users[self.getindexname(who)]
            self.__public_cards.remove(find_cards[0])
            u['hand'].append(find_cards[0])
            self.systoall('%s takes public card [%s]' % (self.getdisplayname(who), self.readCard(find_cards[0])))
        else:
            self.systoone(who, 'Cannot find specified card [%s] in public' % request_card)

    def putHandler(self, who, msg):
        '"/put card_name" put a card.'
        if not self.__game_flag:
            self.systoone(who, 'Please wait until the game starts.')
            return
        u = self.__users[self.getindexname(who)]
        request_card = msg.strip()
        find_cards = self.findCards(request_card, u['hand'])
        if len(find_cards) > 0:
            u['hand'].remove(find_cards[0])
            self.__draw_cards.append(find_cards[0])
            self.systoall('%s put a card [%s].' % (self.getdisplayname(who), request_card))
        else:
            self.systoone(who, 'Cannot find specified card [%s] in your hand.' % request_card)

    def namesHandler(self, who, msg):
        "/names"
        if not self.__game_flag:
            self.systoone(who, 'Please wait until the game starts.')
            return
        arr = []
        for user in self.user_list:
            u = self.__users[user]
            arr.append (self.readPlayerBasic(user, u, (self.getindexname(user)==self.getindexname(who))))
            
        self.systoone(who, '\n'.join(arr))

    def listHandler(self, who, msg):
        "/list"
        if not self.__game_flag:
            self.systoone(who, 'Please wait until the game starts.')
            return
        u = self.__users[self.getindexname(who)]
        self.systoone(who, '== In your hand ==\n' + self.readCards(u['hand']))
        self.systoone(who, '== Equipped ==\n' + self.readCards(u['equip']))

    def listpublicHandler(self, who, msg):
        '"/listpublic" list cards in public'
        if not self.__game_flag:
            self.systoone(who, 'Please wait until the game starts.')
            return
        self.systoone(who, '== Public Cards ==\n' + self.readCards(self.__public_cards))

    def lookHandler(self, who, msg):
        '"/look [player]" show info about player.'
        if not self.__game_flag:
            self.systoone(who, 'Please wait until the game starts.')
            return
        request_player = msg.strip()
        if len(request_player) == 0:
            request_player = self.getdisplayname(who)
        elif self.getindexname(request_player) not in self.user_list:
            self.systoone(who, 'Cannot find specified player %s' % request_player)
            return

        u = self.__users[self.getindexname(request_player)]
        if self.getindexname(request_player) == self.getindexname(who):
            self.systoone(who, '%s\n== Ability ==\n%s\n== Equipments ==\n%s' % (
                self.readPlayerBasic(request_player, u, showrole=True),
                self.readPlayerAbility(u),
                self.readCards(u['equip'])
                ))
        else:
            self.systoone(who, '%s\n== Ability ==\n%s\n== Equipments ==\n%s' % (
                self.readPlayerBasic(request_player, u),
                self.readPlayerAbility(u),
                self.readCards(u['equip'])
                ))

    def endHandler(self, who, msg):
        '"/end" end the game. only for admin.'
        if self.getindexname(who) != self.__admin:
            self.systoone(who, 'Only for admin.')
        else:
            self.systoall('The End!')
            raise DISCARD_COMMAND

    def readPlayerBasic(self, name, player, showrole=False):
        if player['is_sheriff']:
            showrole=True
        return '%s (%s) %s [hp %d] [hand %d] [equip %d]' % (
            name,
            player['character']['Name'],
            showrole and player['role']['Name'] or '',
            player['hp'],
            len(player['hand']),
            len(player['equip'])
            )

    def readPlayerAbility(self, player):
        return player['character']['Text']

    def readCards(self, cards):
        arr = []
        map(arr.append, [self.readCard(card) for card in cards])
        return len(arr) > 0 and '\n'.join(arr) or 'No cards.'

    def readCard(self, card):
        return '%s %s (%s %s)' % (
            card['Color'] == 'Blue' and (card['Type'] == 'Gun' and '[EG%s]' % card['Range'] or '[EN]') or '',
            card['CardName'],
            card['Suit'],
            card['Rank']
            )

    
